﻿using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using Authorize.Core.Entity;
using Authorize.Core.Extensions;
using Authorize.Core.Repository;
using IdentityModel;

namespace Authorize.Core.Store
{
    public class UserStore
    {
        public UserEntity AutoProvisionUser(string provider, string openId, List<Claim> claims)
        {
            var user = new UserEntity();
            var filtered = new List<Claim>();

            switch (provider)
            {
                case "Wechat":
                    user.WeiChatOpenId = openId;
                    break;
            }

            foreach (var claim in claims)
            {
                if (claim.Type == ClaimTypes.Name)
                {
                    filtered.Add(new Claim(JwtClaimTypes.Name, claim.Value));
                }
                else if (JwtSecurityTokenHandler.DefaultOutboundClaimTypeMap.ContainsKey(claim.Type))
                {
                    filtered.Add(
                        new Claim(JwtSecurityTokenHandler.DefaultOutboundClaimTypeMap[claim.Type], claim.Value));
                }
                else
                {
                    filtered.Add(claim);
                }
            }

            if (filtered.All(x => x.Type != JwtClaimTypes.Name))
            {
                var first = filtered.FirstOrDefault(x => x.Type == JwtClaimTypes.GivenName)?.Value;
                var last = filtered.FirstOrDefault(x => x.Type == JwtClaimTypes.FamilyName)?.Value;
                if (first != null && last != null)
                {
                    filtered.Add(new Claim(JwtClaimTypes.Name, first + " " + last));
                }
                else if (first != null)
                {
                    filtered.Add(new Claim(JwtClaimTypes.Name, first));
                }
                else if (last != null)
                {
                    filtered.Add(new Claim(JwtClaimTypes.Name, last));
                }
            }
            user.Id = Guid.NewGuid();
            user.Nickname = filtered.FirstOrDefault(x => x.Type == JwtClaimTypes.Name)?.Value;
            user.CreateDate = DateTime.Now;
            user.UpdateDate = DateTime.Now;

            using (var context = new AuthDbContext())
            {
                context.Users.Add(user);
                context.SaveChanges();
            }

            return user;
        }

        public UserEntity FindByExternalProvider(string provider, string openId)
        {
            using (var context = new AuthDbContext())
            {
                return context.Users.FirstOrDefault(x => x.WeiChatOpenId == openId);
            }
        }

        public UserEntity FindBySubjectId(string subjectId)
        {
            using (var context = new AuthDbContext())
            {
                return context.Users.FirstOrDefault(x => x.Id.ToString() == subjectId);
            }
        }

        public UserEntity FindByUsername(string username)
        {
            using (var context = new AuthDbContext())
            {
                return context.Users.FirstOrDefault(x => x.Username == username);
            }
        }

        public bool ValidateCredentials(string username, string password)
        {
            using (var context = new AuthDbContext())
            {
                var user = context.Users.FirstOrDefault(x =>
                    x.Username == username && x.Password.Equals(password.Md5Hash()));
                return user != null;
            }
        }

        public bool Register(UserEntity user)
        {
            user.Id = Guid.NewGuid();
            user.CreateDate = DateTime.Now;
            user.UpdateDate = DateTime.Now;          
            user.Password = user.Password.Md5Hash();
            using (var context = new AuthDbContext())
            {
                context.Users.Add(user);
                context.SaveChanges();
            }
            return true;
        }

        public bool CheckUsername(string username)
        {
            using (var context = new AuthDbContext())
            {
                var user = context.Users.FirstOrDefault(x => x.Username == username);
                return user == null;
            }
        }

        public bool CheckPhone(string phoneNum)
        {
            using (var context = new AuthDbContext())
            {
                var user = context.Users.FirstOrDefault(x => x.Phone == phoneNum);
                return user == null;
            }
        }
    }
}
